package com.chart.web.controller.chart;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chart.chart.domian.*;
import com.chart.chart.domian.ChartConfigsAndViewsVo;
import com.chart.chart.domian.vo.*;
import com.chart.chart.service.*;
import com.chart.common.constant.CacheConstants;
import com.chart.common.constant.Constants;
import com.chart.common.constant.WeChatConstants;
import com.chart.common.core.controller.BaseController;
import com.chart.common.core.domain.AjaxResult;
import com.chart.common.core.domain.entity.SysUser;
import com.chart.common.core.domain.model.LoginUser;
import com.chart.common.core.page.TableDataInfo;
import com.chart.common.core.redis.RedisCache;
import com.chart.common.utils.ColorUtils;
import com.chart.common.utils.SecurityUtils;
import com.chart.common.utils.sms.SmsSendUtils;
import com.chart.framework.web.service.TokenService;
import com.chart.system.service.ISysUserService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jdk.nashorn.internal.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.awt.*;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 图表
 *
 * @author chart
 */
@RestController
@RequestMapping("/chart")
public class ChartController extends BaseController
{

    @Autowired
    private IChartConfigsService chartConfigsService;

    @Autowired
    private IChartConfigsUserService chartConfigsUserService;

    @Autowired
    private IChartThemeService chartThemeService;


    @Autowired
    private IChartTypeService chartTypeService;

    @Autowired
    private IChartTechnologyService chartTechnologyService;


    @Autowired
    private IChartViewsUserService chartViewsUserService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IChartStatisticsService statisticsService;


    @Autowired
    private IChartThemeService themeService;

    @Autowired
    private TokenService tokenService;

    // 令牌有效期（默认30分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    @ApiOperation("技术领域信息")
    @GetMapping("/technology/info")
    @Transactional
    public AjaxResult technologyInfo(ChartTechnology chartTechnology)
    {
        ChartTechnology technology = chartTechnologyService.getOne(new LambdaQueryWrapper<ChartTechnology>().eq(ChartTechnology::getId, chartTechnology.getId()));
        if (technology.getParentId() !=0) {
            ChartTechnology list1 = chartTechnologyService.getOne(new LambdaQueryWrapper<ChartTechnology>().eq(ChartTechnology::getId, technology.getParentId()));
            list1.setSubset(technology);
            return AjaxResult.success(list1);
        }
        return AjaxResult.error();
    }

    @ApiOperation("技术领域列表")
    @GetMapping("/technology/list")
    @Transactional
    public AjaxResult technologyList(ChartTechnology chartTechnology)
    {
        List<ChartTechnology> list = redisCache.getCacheObject(CacheConstants.CHART_TECHNOLOGY);
        return AjaxResult.success(list);
    }


    @ApiOperation("我的生成：列表(图表和大屏)")
    @GetMapping("/all/list")
    @Transactional
    public TableDataInfo allList(ChartConfigsUser configsUser)
    {
          configsUser.setUserId(SecurityUtils.getUserId());
          List<ChartConfigsAndViewsVo> ccav=chartConfigsUserService.getChartsAndViews(configsUser);
          return getDataTable(ccav);
    }

    @ApiOperation("图表渐变主题列表plus")
    @GetMapping("/theme/getGradientPlus")
    public AjaxResult getGradientPlus(Integer[] colorNums)
    {
//        List<ChartTheme> chartThemes = themeService.list(new LambdaQueryWrapper<ChartTheme>().orderByAsc(ChartTheme::getThemeType).orderByAsc(ChartTheme::getSort));
        List<List<ChartTheme>> newList = new ArrayList<>();
        for (Integer colorNum : colorNums) {
            List<ChartTheme> chartThemes = redisCache.getCacheObject(CacheConstants.CHART_THEME);
            for (int i1 = 0; i1 < chartThemes.size(); i1++) {
                ChartTheme chartTheme = chartThemes.get(i1);
                String themeValue = chartTheme.getThemeValue();
                JSONObject jsonObject = JSONObject.parseObject(themeValue);
                List<String> colors = (List<String>) jsonObject.get("color");
                //判断数据是否已经超出了预设主题配色
                if (colorNum>colors.size()) {
                    //根据主题颜色获取过渡色
                    List<String> gradientColors = ColorUtils.generateGradientColors(colors, colorNum);
                    jsonObject.put("color",gradientColors);
                    chartTheme.setThemeValue(JSONObject.toJSONString(jsonObject));
                }
            }
            newList.add(chartThemes);
        }
        return AjaxResult.success(newList);
    }

    @ApiOperation("图表渐变主题列表p")
    @GetMapping("/theme/getGradients")
    public AjaxResult themeList(Integer colorNum)
    {
//        List<ChartTheme> chartThemes = themeService.list(new LambdaQueryWrapper<ChartTheme>().orderByAsc(ChartTheme::getThemeType).orderByAsc(ChartTheme::getSort));
        List<ChartTheme> chartThemes = redisCache.getCacheObject(CacheConstants.CHART_THEME);
        for (int i = 0; i < chartThemes.size(); i++) {
            ChartTheme chartTheme = chartThemes.get(i);
            String themeValue = chartTheme.getThemeValue();
            JSONObject jsonObject = JSONObject.parseObject(themeValue);
            List<String> colors = (List<String>) jsonObject.get("color");
            //判断数据是否已经超出了预设主题配色
            if (colorNum>colors.size()) {
                //根据主题颜色获取过渡色
                List<String> gradientColors = ColorUtils.generateGradientColors(colors, colorNum);
                jsonObject.put("color",gradientColors);
                chartTheme.setThemeValue(JSONObject.toJSONString(jsonObject));
            }
        }
        return AjaxResult.success(chartThemes);
    }

    @ApiOperation("图表渐变主题列表")
    @GetMapping("/theme/getGradientList")
    public AjaxResult themeList(Integer colorNum,Long themeId)
    {
        ChartTheme chartTheme = redisCache.getCacheObject(CacheConstants.CHART_THEME + themeId);
        String themeValue = chartTheme.getThemeValue();
        JSONObject jsonObject = JSONObject.parseObject(themeValue);
        List<String> colors = (List<String>) jsonObject.get("color");
        if (colorNum>colors.size()) {
            List<String> gradientColors = ColorUtils.generateGradientColors(colors, colorNum);
            jsonObject.put("color",gradientColors);
            chartTheme.setThemeValue(JSONObject.toJSONString(jsonObject));
        }
        return AjaxResult.success(chartTheme);
    }


    @ApiOperation("图表主题列表")
    @GetMapping("/theme/list")
    @Transactional
    public AjaxResult themeList(ChartTheme chartTheme)
    {
        List<ChartTheme> list =null;
        if (ObjectUtils.isEmpty(chartTheme.getThemeType())) {
            list = redisCache.getCacheObject(CacheConstants.CHART_THEME);
        }else {
            list = redisCache.getCacheObject(CacheConstants.CHART_THEME+chartTheme.getThemeType());
        }

//        List<ChartTheme> list = chartThemeService.list(new LambdaQueryWrapper<ChartTheme>().orderByAsc(ChartTheme::getSort));
        return AjaxResult.success(list);
    }

    @ApiOperation("图表列表")
    @GetMapping("/config/list")
    @Transactional
    public AjaxResult configList(ChartConfigs chartConfigs)
    {
        ChartsVo chartsVo = new ChartsVo();
        ArrayList<ChartMenuVo> chartMenuVos = new ArrayList<>();

        ArrayList<ChartListVo> chartListVos = new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            ChartMenuVo chartMenuVo = new ChartMenuVo();
            if (i==0) {
                chartMenuVo.setLabel("通用模版");
                List<ChartType> list = chartTypeService.list(new LambdaQueryWrapper<ChartType>().ne(ChartType::getId, 15).ne(ChartType::getStatus,1).orderByAsc(ChartType::getSort));
                for (int i1 = 0; i1 < list.size(); i1++) {
                    ChartType chartType = list.get(i1);
//                    List<ChartConfigs> list1 = chartConfigsService.list(new LambdaQueryWrapper<ChartConfigs>().eq(ChartConfigs::getChartTypeId, chartType.getId()));
                    //根据类型获取图表配置信息
                    List<ChartConfigs> list1 =chartConfigsService.getBriefList(chartType.getId());
                    ChartListVo chartListVo = new ChartListVo();
                    chartListVo.setLabel(chartType.getName());
                    chartListVo.setList(list1);
                    chartListVos.add(chartListVo);
                }
                chartMenuVo.setChildren(list);
            }else {
                chartMenuVo.setLabel("专家模版");
                List<ChartType> list = chartTypeService.list(new LambdaQueryWrapper<ChartType>().eq(ChartType::getId, 15).ne(ChartType::getStatus,1));
                for (int i1 = 0; i1 < list.size(); i1++) {
                    ChartType chartType = list.get(i1);
//                    List<ChartConfigs> list1 = chartConfigsService.list(new LambdaQueryWrapper<ChartConfigs>().eq(ChartConfigs::getChartTypeId, chartType.getId()));
                    List<ChartConfigs> list1 =chartConfigsService.getBriefList(chartType.getId());
                    ChartListVo chartListVo = new ChartListVo();
                    chartListVo.setLabel(chartType.getName());
                    chartListVo.setList(list1);
                    chartListVos.add(chartListVo);
                }
                chartMenuVo.setChildren(list);
            }
            chartMenuVos.add(chartMenuVo);
        }
        chartsVo.setMenuList(chartMenuVos);
        chartsVo.setChartsList(chartListVos);
        return AjaxResult.success(chartsVo);
    }


    @ApiOperation("图表详情")
    @GetMapping("/config/info")
    @Transactional
    public AjaxResult configInfo(ChartConfigs chartConfigs)
    {
        ChartConfigs configs = chartConfigsService.getById(chartConfigs.getId());
        return AjaxResult.success(configs);
    }





    @ApiOperation("智能大屏列表")
    @GetMapping("/user/configList")
    @Transactional
    public TableDataInfo userconfigList(ChartConfigsUserVo chartConfigsUserVo)
    {
//        List<ChartConfigsUser> list = chartConfigsUserService.list(new LambdaQueryWrapper<ChartConfigsUser>().eq(ChartConfigsUser::getUserId,SecurityUtils.getUserId()));
        chartConfigsUserVo.setUserId(SecurityUtils.getUserId());
        startPage();
        List<ChartConfigsUserVo> list =chartConfigsUserService.getListWithOutValue(chartConfigsUserVo);
        return getDataTable(list);
    }

    @ApiOperation("我的生成：新增")
    @PostMapping("/user/add")
    @Transactional
    public AjaxResult add(@RequestBody ChartConfigsUser configsUser)
    {
        if (ObjectUtils.isEmpty(configsUser.getChartName())) {
            return AjaxResult.error("请填写图表名称");
        }
        ChartConfigsUser one =null;
        if (ObjectUtils.isEmpty(configsUser.getFileId())) {
            one = chartConfigsUserService.getOne(new LambdaQueryWrapper<ChartConfigsUser>().eq(ChartConfigsUser::getChartName, configsUser.getChartName())
                    .eq(ChartConfigsUser::getUserId,SecurityUtils.getUserId()).isNull(ChartConfigsUser::getFileId));
        }else {
            one = chartConfigsUserService.getOne(new LambdaQueryWrapper<ChartConfigsUser>().eq(ChartConfigsUser::getChartName, configsUser.getChartName())
                    .eq(ChartConfigsUser::getUserId,SecurityUtils.getUserId()).eq(ChartConfigsUser::getFileId,configsUser.getFileId()));
        }

        if (!ObjectUtils.isEmpty(one)) {
            return AjaxResult.error("图表名称重复");
        }
        configsUser.setUserId(SecurityUtils.getUserId());
        return AjaxResult.success(chartConfigsUserService.save(configsUser));
    }


    @ApiOperation("我的生成：修改")
    @PostMapping("/user/edit")
    @Transactional
    public AjaxResult edit(@RequestBody ChartConfigsUser configsUser)
    {
        if (ObjectUtils.isEmpty(configsUser.getChartName())) {
            return AjaxResult.error("请填写图表名称");
        }
        ChartConfigsUser one = chartConfigsUserService.getOne(new LambdaQueryWrapper<ChartConfigsUser>().
                eq(ChartConfigsUser::getChartName, configsUser.getChartName())
                .ne(ChartConfigsUser::getId,configsUser.getId()).
                eq(ChartConfigsUser::getUserId,SecurityUtils.getUserId()).
                eq(!ObjectUtils.isEmpty(configsUser.getFileId()),ChartConfigsUser::getFileId,configsUser.getFileId()));
        if (!ObjectUtils.isEmpty(one)) {
            return AjaxResult.error("图表名称重复");
        }
        return AjaxResult.success(chartConfigsUserService.saveOrUpdate(configsUser));
    }
    @ApiOperation("我的生成：根据id获取单个图表详情")
    @GetMapping("/user/getInfo")
    public AjaxResult getInfo(ChartConfigsUser configsUser)
    {
        ChartConfigsUser one = chartConfigsUserService.getOne(new LambdaQueryWrapper<ChartConfigsUser>().eq(ChartConfigsUser::getId, configsUser.getId()));
        ChartConfigs configs = chartConfigsService.getById(one.getConfigId());
        one.setTemplateUrl(configs.getTemplateUrl());
        if (!ObjectUtils.isEmpty(one.getTechnologyId())) {
            ChartTechnology technology = chartTechnologyService.getById(one.getTechnologyId());
            one.setTechnologyName(technology.getTechnologyName());
        }
        return AjaxResult.success(one);
    }

    @ApiOperation("我的生成：根据id删除（支持批量）")
    @PostMapping("/user/del")
    @Transactional
    public AjaxResult del(@RequestBody ChartConfigsUser configsUser)
    {
        return AjaxResult.success(chartConfigsUserService.removeByIds(configsUser.getIds()));
    }


    @ApiOperation("图表类型列表")
    @GetMapping("/type/list")
    @Transactional
    public AjaxResult typeList()
    {
        ChartType list = redisCache.getCacheObject(CacheConstants.CHART_TYPE);
        return AjaxResult.success(list);
//        return AjaxResult.success(chartTypeService.list(new LambdaQueryWrapper<ChartType>().orderByAsc(ChartType::getSort)));
    }



    @ApiOperation("获取操作权限")
    @GetMapping("/getoperPower")
    @Transactional
    public AjaxResult getoperPower(Integer isFree) {
        //判断图表是否免费
        if (isFree==0) {
            return AjaxResult.success(WeChatConstants.OK);
        }else {
            if (SecurityUtils.isAdmin()) {
                return AjaxResult.success(WeChatConstants.OK);
            } else if (SecurityUtils.isVip()) {
                return AjaxResult.success(WeChatConstants.OK);
            } else {
                Long userId = SecurityUtils.getUserId();
                SysUser user = userService.getById(userId);

                if (!ObjectUtils.isEmpty(user.getOpenId())) {
                    if (!ObjectUtils.isEmpty(user.getIsSubscribe())) {
                        Integer freeOper = user.getFreeOper();
                        if (freeOper == 0 && ObjectUtils.isEmpty(user.getEmail())) {
                            //完善信息
                            return AjaxResult.success(WeChatConstants.IMPROVE_INFORMATION);
                        } else if (freeOper == 0 && !ObjectUtils.isEmpty(user.getEmail()) && user.getIsForward() == 0) {
                            //转发推文
                            return AjaxResult.success(WeChatConstants.FORWARD_TWEETS);
                        } else if (freeOper == 0 && user.getIsForward() == 1) {
                            //开通vip
                            return AjaxResult.success(WeChatConstants.AC_VIP);
                        }else if (freeOper > 0) {
                            freeOper= freeOper - 1;
                            user.setFreeOper(freeOper);
                            boolean result = userService.saveOrUpdate(user);
                            if (result) {
                                return AjaxResult.success(freeOper);
                            }
                        }
                    }  else {
                        //关注微信公众号
                        return AjaxResult.success(WeChatConstants.FOLLOW_WECHAT_OFFICIAL_ACCOUNT);
                    }
                }else {
                    //绑定微信
                    return AjaxResult.success(WeChatConstants.BIND_WECHAT);
                }
            }
        }
        return AjaxResult.error();
    }


    @ApiOperation("通过转发获取操作次数")
    @GetMapping("/getoperByforward")
    @Transactional
    public AjaxResult getoperByforward()
    {
        Long userId = SecurityUtils.getUserId();
        SysUser user = userService.getById(userId);
        if (!ObjectUtils.isEmpty(user.getIsSubscribe())) {
            if (user.getIsForward()==0) {
                Integer freeOper = user.getFreeOper();
                user.setFreeOper(freeOper+3);
                user.setIsForward(1);
                boolean result = userService.saveOrUpdate(user);
                if (result) {
                    return AjaxResult.success("转发成功，已经获得3次免费导出");
                }
            }else {
                //该账号已经进行转发，无法再次获得操作次数
                return AjaxResult.success("转发成功（只有第一次转发才可获取免费导出）");
            }
        }
        //关注微信公众号
        return AjaxResult.success(WeChatConstants.FOLLOW_WECHAT_OFFICIAL_ACCOUNT);
    }





    @ApiOperation("保存用户操作记录")
    @PostMapping("/oper/save")
    @Transactional
    public AjaxResult oper(@RequestBody ChartStatistics chartStatistics)
    {
        chartStatistics.setUserId(SecurityUtils.getUserId());
        boolean save = statisticsService.save(chartStatistics);
        if (save) {
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }

    @ApiOperation("获取图表数据上传地址")
    @GetMapping("/getDataAddr")
    @Transactional
    public AjaxResult getInterface(Long configId)
    {
          return AjaxResult.success(redisCache.getCacheObject(CacheConstants.CHART_INTERFACE+configId));
    }

    @ApiOperation("保存用户点击‘我知道了’操作记录")
    @PostMapping("/oper/notice")
    @Transactional
    public AjaxResult notice()
    {
        if (SecurityUtils.isNoticed()) {
            return AjaxResult.success();
        }
        SysUser sysUser = new SysUser();
        sysUser.setFirstNotice(1);
        sysUser.setUserId(SecurityUtils.getUserId());
        boolean save = userService.saveOrUpdate(sysUser);
        if (save) {
            refreshToken();
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }




    //将主题、技术领域、图表类型、图表接口等信息进行缓存
    @PostConstruct
    private void extracted() {
        List<ChartTheme> list = themeService.list(new LambdaQueryWrapper<ChartTheme>().orderByAsc(ChartTheme::getThemeType).orderByAsc(ChartTheme::getSort));
//        Map<Integer, List<ChartTheme>> map = list.stream().collect(Collectors.groupingBy(ChartTheme::getThemeType));
//        map.forEach((key,value)->{
//            redisCache.setCacheObject(CacheConstants.CHART_THEME+key,map.get(key));
//        });
        redisCache.setCacheObject(CacheConstants.CHART_THEME,list);
        list.stream().forEach(e->{
            redisCache.setCacheObject(CacheConstants.CHART_THEME+e.getId(),e);
        });



        List<ChartTechnology> technologyList = chartTechnologyService.list(new LambdaQueryWrapper<ChartTechnology>().eq(ChartTechnology::getParentId, 0));
        for (int i = 0; i < technologyList.size(); i++) {
            ChartTechnology chartTechnology1 = technologyList.get(i);
            List<ChartTechnology> list1 = chartTechnologyService.list(new LambdaQueryWrapper<ChartTechnology>().eq(ChartTechnology::getParentId, chartTechnology1.getId()));
            chartTechnology1.setChildren(list1);
        }
        redisCache.setCacheObject(CacheConstants.CHART_TECHNOLOGY,technologyList);


        List<ChartType> typeList = chartTypeService.list(new LambdaQueryWrapper<ChartType>().orderByAsc(ChartType::getSort));
        redisCache.setCacheObject(CacheConstants.CHART_TYPE,typeList);

        List<ChartConfigsInterface> faces=chartConfigsService.getChartInterfaces();
        faces.forEach(e->{
            String configAddr = e.getConfigAddr();
            if (!ObjectUtils.isEmpty(configAddr)) {
                redisCache.setCacheObject(CacheConstants.CHART_INTERFACE+e.getConfigId(),configAddr);
            }
        });
    }

    /**
     * 刷新令牌有效期
     *
     */
    public void refreshToken()
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();

        user.setFirstNotice(1);

        // 根据uuid将loginUser缓存
        String userKey = tokenService.getTokenKey1(loginUser.getToken());

        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }


}
